import { dateUtil } from './dateUtil'
import { GanZhi } from './ganzhi'

/**
 * @constant
 * @description 实例化一个ChinaDate对象
 * @param {int} theYear alt 年份(1900~2099)
 * @param {int} theMonthInner alt 内部月份数(1~12或1~13)
 * @param {int} theLeapMonth alt 润月数(0~12. 0表示此年无润月)
 * @param {int} theDay alt 日数(1~29或1~30)
 * @param {int} theHour alt 时辰索引(0~11)
 * @return {ChinaDate}
 */
export class ChinaDate {
	/**
	 * @description 年数(1910~2099)
	 * @type {int}
	 */
	Year : number;
	/**
	 * @description 内部月份数 ( 1 ~ 12 或 1 ~ 13 ). 注意:润月及之后的内部月份数比显示数大 1
	 * @type {int}
	 */
	MonthInner : number;
	/**
	 * @description 润月数 ( 0 ~ 13 ). 0 表示此年没有润月
	 * @type {int}
	 */
	LeapMonth : number;
	/**
	 * @description 天数 ( 1 ~ 29 或 1 ~ 30 )
	 * @type {int}
	 */
	Day : number;
	/**
	 * @description 时辰索引 ( 0 ~ 11 )
	 * @type {int}
	 */
	Hour : number;
	constructor(theYear : number, theMonthInner : number, theLeapMonth : number, theDay : number, theHour : number) {
		this.Year = theYear;
		this.MonthInner = theMonthInner;
		this.LeapMonth = theLeapMonth;
		this.Day = Math.floor(theDay);
		this.Hour = theHour;
	}
	/**
	 * @description 获取农历的显示月份数(1~12)
	 * @return {int}
	 */
	getMonthDisplay() : number {
		return this.LeapMonth > 0 && this.MonthInner >= this.LeapMonth ? this.MonthInner - 1 : this.MonthInner;
	};
	/**
	 * @description 如果当前月份为润月,返回true
	 * @return {bool}
	 */
	MonthIsLeap() : boolean {
		return this.LeapMonth == this.MonthInner;
	};
	getMonthText() : string {
		console.log("ChinaDate.getMonthText: 显示月份数: " + (this.getMonthDisplay()?.toString() ?? "") + " 闰月数: " + (this.LeapMonth?.toString() ?? ""))
		return ChinaDate.getMonthText(this.getMonthDisplay(), this.MonthIsLeap());
	};
	getDayText() : string {
		return ChinaDate.getDayText(this.Day);
	}
	/**
	 * @description 获取农历日的显示文本
	 * @param {Int} theDay alt 农历日数(1~29 或 1~30)
	 * @return {String}
	 */
	static getDayText(theDay : number) : string {
		return "初一初二初三初四初五初六初七初八初九初十十一十二十三十四十五十六十七十八十九二十廿一廿二廿三廿四廿五廿六廿七廿八廿九三十".substring((theDay - 1) * 2, (
			theDay - 1) * 2 +
			2);
	};
	/**
	 * @description 获取农历月份的显示文本. 注意:这里的月份是显示月份数
	 * @param {int} theMonth alt 农历月数(显示数.1~12)
	 * @param {bool} theIsLeapMonth 是否为润月
	 * @return {String}
	 */
	static getMonthText(theMonth : number, theIsLeapMonth : boolean) : string {
		return (theIsLeapMonth ? "闰" : "  ") + "正二三四五六七八九十冬腊".charAt(theMonth - 1) + "月";
	};

	/**
	 * @description 获取农历月份的显示文本. 注意:这里的月份数是内部数据表示法
	 * @param {int} theMonthIndex 月份索引(1~12或1~13)
	 * @param {int} theLeapMonth 闰月数(0~13)
	 * @return {String}
	 */
	static getMonthTextByIndex(theMonthIndex : number, theLeapMonth : number) : string {
		var dMonth = theMonthIndex;
		var dIsLeap = theMonthIndex == theLeapMonth;
		if (theLeapMonth > 0 && dMonth >= theLeapMonth) dMonth -= 1;
		return ChinaDate.getMonthText(dMonth, dIsLeap);
	};
	/**
	 * @description 从公历获取农历对象. 此方法返回的时辰固定为子时
	 * @param {Date} theDate alt 公历日期
	 * @return {ChinaDate}
	 */
	static getChinaDate(theDate : Date) : ChinaDate {
		var dYear = theDate.getFullYear();
		//初一的偏移天数
		var dZero = dateUtil.getZeroStart(dYear);
		//当前日期的偏移天数
		var dDays0 = dateUtil.getDaysOfYear(theDate) - 1;
		if (dDays0 < dZero) {
			dYear -= 1;
			dZero = dateUtil.getZeroStart(dYear);
			dDays0 += 365 + (dateUtil.dateIsLeapYear(dYear) ? 1 : 0);
		}
		var dDays = dDays0 - dZero;
		var dMonth = 1;
		for (var xx = 1; xx < 13; xx++) {
			var nn = dateUtil.getDaysInMonth(dYear, xx);
			if (nn > dDays) break;
			dDays -= nn;
			dMonth += 1;
		}
		return new ChinaDate(dYear, dMonth, dateUtil.getLeapMonth(dYear), dDays + 1, 0);
	};
	/**
	 * @description 从农历对象返回农历的显示信息(加属相,不包含时辰)
	 * @return {String}
	 */
	getText() : string {
		return GanZhi.getYearGanZhi(this.Year).getText() + "年(" +
			dateUtil.getYearProperty(this.Year) + ")  " +
			ChinaDate.getMonthText(this.getMonthDisplay(), this.MonthIsLeap()) +
			ChinaDate.getDayText(this.Day);
	};
	/**
	 * @description 从农历年月日获取农历日期信息. (从显示月份计算. 加属相,不包含时辰)
	 * @param {int} theYear alt 年份. 必须在1901 ~ 2100之间(包含). 
	 * @param {int} theDesplayMonth alt 月份. 1 ~ 12,注意:这里的月份是显示月份. 
	 * @param {bool} theMonthLeap alt 润月. bool,只有润月才应该为true. 
	 * @param {int} theDay 日数. 1 ~ 29(小月)或1~30(大月). 
	 * @return {String}
	 */
	static getTextByDisplay(theYear : number, theDesplayMonth : number, theMonthLeap : boolean, theDay : number) : string {
		return GanZhi.getYearGanZhi(theYear).getText() + "年(" + dateUtil.getYearProperty(theYear) + ")  " +
			ChinaDate.getMonthText(theDesplayMonth, theMonthLeap) + ChinaDate.getDayText(theDay);
	};
	/**
	 * @description 从农历获取公历
	 * @param {int} theYear 年份. 必须在 1901 ~ 2100 之间 ( 包含 )
	 * @param {int} theMonth 内部月份. 1 ~ 12 或者 1 ~ 13 ( 闰月时 ) , 注意 : 闰月及之后的月数比显示数大 1
	 * @param {int} theDay 日数. 1 ~ 29 ( 小月 ) 或 1 ~ 30 ( 大月 )
	 * @return {Date}
	 */
	static getDateFromChina(theYear : number, theMonth : number, theDay : number) : Date {
		if (theMonth < 1 || theMonth > 13) {
			throw ("ChinaDate->getDateFromChina: 月份必须在1~13之间,当前的值为" + (theMonth?.toString() ?? ""));
		}
		if (theDay < 1 || theDay > 30) {
			throw ("ChinaDate->getDateFromChina: 日数必须在1~30之间,当前的值为" + (theDay?.toString() ?? ""));
		}
		var dDays = dateUtil.getZeroStart(theYear);
		for (var xx = 1; xx < theMonth; xx++) {
			dDays += dateUtil.getDaysInMonth(theYear, xx);
		}
		dDays += theDay - 1;

		var dDate = new Date(theYear, 0, dDays + 1);

		return dDate;
	};
	/**
	 * 从农历对象获取公历
	 */
	 toDate() : Date {
		var dDays = dateUtil.getZeroStart(this.Year);
		for (var xx = 1; xx < this.MonthInner; xx++) {
			dDays += dateUtil.getDaysInMonth(this.Year, xx);
		}
		dDays += this.Day - 1;

		var dDate = new Date(this.Year, 0, dDays + 1);
		return dDate;
	}
	/**
	 * @description 从公历获取农历信息.
	 * @param {Date} theDate alt 月份数(1~12)
	 * @return {String}
	 */
	static getChinaTextByDate(theDate : Date) : string {
		return ChinaDate.getChinaDate(theDate).getText();
	};
	/**
	 * @description 从农历的显示月份计算农历的月份内部计数(1~12或1~13)
	 * @param {int} theYear alt 农历年数(1910~2069)
	 * @param {int} theMonth alt 农历月数(1~12)
	 * @param {bool} isLeapMonth alt 是否为润月
	 * @return {int}
	 */
	static getMonthInnerFromDisplay(theYear : number, theMonth : number, isLeapMonth : boolean) : number {
		var dLeap = dateUtil.getLeapMonth(theYear);
		var dMonth = theMonth;
		if (dLeap > 0 && theMonth > dLeap) dMonth++;
		if (dLeap > 0 && theMonth == dLeap && isLeapMonth) dMonth++;
		return dMonth;
	};

	/**
	 * @description 从农历月份的内部计数(1~12或1~13)计算农历的显示月份数(1~12)
	 * @param {int} theYear alt 农历年数(1910~2069)
	 * @param {int} theMonth alt 农历月份显示数
	 * @return {int}
	 */
	static getMonthDisplayFromInner(theYear : number, theMonth : number) : number {
		var dLeap = dateUtil.getLeapMonth(theYear);
		if (dLeap == 0 || dLeap > theMonth) {
			return theMonth;
		} else {
			return theMonth - 1;
		}
	};

}